#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "imageprocess.h"

void Threshold(unsigned char *pTo, unsigned char *pSourse, unsigned int biHight, unsigned int biWidth, unsigned char nThres)
{
    int i,j;
    unsigned char bt;

    for(i=0;i<biHight;i++)
    {
        for(j=0;j<biWidth;j++)
        {
            bt = pSourse[i*biWidth+j];

            if(bt<nThres)
                bt = 0;
            else
                bt = 255;

            pTo[i*biWidth+j] = bt;
        }
    }
}

int DetectThreshold(unsigned char *pSourse, unsigned int biHight, unsigned int biWidth, int nMaxIter, int *nDiffRet)
{
    unsigned char nThreshold;
    unsigned int i,j;
    unsigned char bt;
    unsigned char nMin = 255;
    unsigned char nMax = 0;
    unsigned int nTotalGray;
    unsigned int nTotalPixel;
    unsigned char nNewThreshold;
    unsigned int nIterationTimes;
    unsigned char nMeanlGrayValue;
    unsigned char nMean2GrayValue;
    unsigned char nHistogram[255] = {0};

    *nDiffRet = 0;


    for(j=0;j<biHight;j++)
    {
        for(i=0;i<biWidth;i++)
        {
            bt = pSourse[j*biWidth+i];

            if(bt < nMin)
                nMin = bt;
            if(bt > nMax)
                nMax = bt;

            nHistogram[bt]++;
        }
    }

    nTotalGray = 0;
    nTotalPixel = 0;
    nNewThreshold = (nMax+nMin)/2;

    *nDiffRet = nMax - nMin;
    if(nMax==nMin)
        nThreshold = nNewThreshold;
    else
    {
        nThreshold = 0;
        for(nIterationTimes=0;nThreshold!=nNewThreshold&&nIterationTimes<nMaxIter;nIterationTimes++)
        {
            nThreshold = nNewThreshold;
            nTotalGray = 0;
            nTotalPixel = 0;

            for(i=nMin;i<nThreshold;i++)
            {
                nTotalGray += nHistogram[i]*i;
                nTotalPixel += nHistogram[i];
            }
            nMeanlGrayValue = nTotalGray/nTotalPixel;
            nTotalGray = 0;
            nTotalPixel = 0;

            for(i=nThreshold+1;i<=nMax;i++)
            {
                nTotalGray += nHistogram[i]*i;
                nTotalPixel += nHistogram[i];
            }

            nMean2GrayValue =  nTotalGray/nTotalPixel;
            nNewThreshold = (nMeanlGrayValue + nMean2GrayValue)/2;
            *nDiffRet = abs(nMeanlGrayValue - nMean2GrayValue);
        }
    }
    return nThreshold;
}

static int GetMedianValue(unsigned char *pAryGray,unsigned int nFilterLen)
{
    unsigned int i,j;
    unsigned char nMedianValue;
    unsigned char nTemp;

    for(j=0;j<nFilterLen-1;j++)
    {
        for(i=0;i<nFilterLen-j-1;i++)
        {
            if(pAryGray[i]>pAryGray[i+1])
            {
                nTemp = pAryGray[i];
                pAryGray[i] = pAryGray[i+1];
                pAryGray[i+1] = nTemp;
            }
        }
    }

    if((nFilterLen&1)>0)
    {
        nMedianValue = pAryGray[(nFilterLen+1)/2];
    }
    else
    {
        nMedianValue = (pAryGray[nFilterLen/2]+pAryGray[nFilterLen/2+1])/2;
    }
    return nMedianValue;
}

void MedianFilter(unsigned char *pTo, unsigned char *pSourse, unsigned int biHight, unsigned int biWidth, unsigned int nFilterH, unsigned int nFilterW, unsigned int nFilterMY, unsigned int nFilterMX)
{
    //clear pTo;
    unsigned int i,j,k,l;
    unsigned int nHeight = biHight;
    unsigned int nWidth = biWidth;
    unsigned char nGray;
    unsigned char *pAryGray;
    pAryGray = (unsigned char *)malloc(nFilterH*nFilterW);
    memset(pAryGray,0,sizeof(unsigned char)*nFilterH*nFilterW);/////////////////////////////////////////

    for(i=nFilterMY;i<nHeight-nFilterH+nFilterMY+1;i++)
    {
        for(j=nFilterMX;j<nWidth-nFilterW+nFilterMX+1;j++)
        {
            for(k=0;k<nFilterH;k++)
            {
                for(l=0;l<nFilterW;l++)
                {
                    nGray = pSourse[nWidth*(i+k-nFilterMY)+j+l-nFilterMX];
                    pAryGray[k*nFilterW+l] = nGray;
                }
            }

            nGray = GetMedianValue(pAryGray,nFilterH*nFilterW);
/****************************************************************************/
if((pSourse[nWidth*i+j]==pAryGray[0])||(pSourse[nWidth*i+j]==pAryGray[nFilterH*nFilterW-1]))
{
    pTo[nWidth*i+j] = nGray;;
}
else
{
    pTo[nWidth*i+j] = pSourse[nWidth*i+j];
}
/****************************************************************************/
        }
    }
    free(pAryGray);
}

void Erode(unsigned char *pTo,unsigned char *pSourse,unsigned int biHight,unsigned int biWidth,float *se,unsigned int nTempH,unsigned int nTempW)
{
    unsigned char Blue;
    //float fCoef;
    bool bMatch;
    unsigned int i,j,ii,jj;


    for(i=0;i<biHight;i++)
    {
        for(j=0;j<biWidth;j++)
        {
            if(i==0||(i==biHight-1)||j==0||j==(biWidth-1))
            {
                Blue = 0xff;
            }
            else
            {
                bMatch = true;

                for(ii=0;ii<nTempH;ii++)
                {
                    for(jj=0;jj<nTempW;jj++)
                    {
                        if(se[ii*nTempW+jj]==-1)
                            continue;
                        if(se[ii*nTempW+jj]==1)
                        {
                            if(pSourse[(biWidth*(i+ii-1)+j+jj-1)]!=0)
                            {
                                bMatch = false;
                                break;
                            }
                        }
                        else if(se[ii*nTempW+jj]==0)
                        {
                            if(pSourse[biWidth*(i+ii-1)+j+jj-1]!=255)
                            {
                                bMatch = false;
                                break;
                            }
                        }
                    }
                }

              if(bMatch==false)
                {
                    Blue = 0xff;
                }
                else
                {
                    Blue = 0x00;
                }
                pTo[biWidth*i+j] = Blue;
            }
        }
    }
}
